﻿(function(window){
var 
	mooluRotate = function(){

		return new muRotate(Array.prototype
							.slice.apply(arguments));
	},

	muRotate = function(arryConfig){
			
		this._init(arryConfig);
			
	};
		
muRotate.prototype = {
		
	_init : function(params){
		var 
			cfg = {},
			len = params.length,
			p, param;
		
		for(var i=1; i<len; i++){
		    
			param = params[i];
			switch(typeof param){
			    
				case 'number':
				
					break;
				case 'string':
				
					break;
				case 'function':
					
					break;
				case 'object':
					
					for(p in param){
					    
						cfg[p] = param[p];
					}
			}
		}
		
		var container = params[0];
		
		this._container = container;
		this._clientWidth = container.clientWidth;
		this._clientHeight = container.clientHeight;
		this._img = new Image();
		this._style = {};
		this._x = this._y = 1;
		this._radian = 0;
		this._support = false;
		
		this._init = this._load = 
		this._show = this._destroy = function(){};
		
		var opt = this._setOptions(cfg);
						
		this._zoom = opt.zoom;
		this.onPreLoad = opt.onPreLoad;
		this.onLoad = opt.onLoad;
		this.onError = opt.onError;
			
		this._LOAD = $$OBEA.bind(function(){
			this.onLoad();
			this._load();
			this.reset();
			this._img.style.visibility = 'visible';
		}, this);
			
		$$OBEA.selfe.fireEvent(this, 'init');	
		this._initMode();
		
		
		
		if(this._support){
			this._initContainer();
			this._init();
		}else{
			this.onError('not support');
		}
		
		$$OBEA.init(this);
		return this;
	},
			
	_setOptions : function(options){
		this.options = {
			mode : 'css3|filter|canvas',
			zoom : .1,
			onPreLoad : function(){},
			onLoad : function(){},
			onError : function(err){}
		};
		
		return $$OBEA.extend(this.options, options || {});
	},
		
	_initMode : function(){
		var modes = muRotate.modes;
		this._support = $$OBEA.some(
			this.options.mode.toLowerCase().split('|'), 
			function(mode){
				mode = modes[mode];
				if(mode && mode.support){
					mode.init && (this._init = mode.init);
					mode.load && (this._load = mode.load);
					mode.show && (this._show = mode.show);
					mode.destroy && (this._destroy = mode.destroy);
					
					$$OBEA.forEach(muRotate.transforms, function(transform, name){
						this[name] = function(){
							transform.apply(this, [].slice.call(arguments));
							this._show();
						}
					}, this);
					
					return true;
				}
			}, this);
	},
	
	_initContainer : function(){
		var 
			container = this._container,
			style = container.style,
			position = $$OBEA.getStyle(container, 'position');
		
		this._style = {'position' : style.position, 
					   'overflow' : style.overflow};
		
		if(position != 'relative' && position != 'absolute'){
			style.position = 'relative';
		}
		
		style.overflow = 'hidden';
		$$OBEA.selfe.fireEvent(this, 'initContainer');
	},
			
	load : function(src){
		if(this._support){
			var 
				img = this._img,
				oThis = this;
			
			
			img.onload || (img.onload = this._LOAD);
			img.onerror || (img.onerror = function(){oThis.onError('err image');});
			img.style.visibility = 'hidden';
			this.onPreLoad();
			img.src = src;
		}
	},
			
	reset : function(){
		if(this._support){
			this._x = this._y = 1;
			this._radian = 0;
			this._show();
		}
	},
			
	destroy : function(){
		if(this._support){
			this._destroy();
			$$OBEA.selfe.fireEvent(this, 'destroy');
			$$OBEA.setStyle(this._container, this._style);
			this._container = this._img = 
			this._img.onload = this._img.onerror = 
			this._LOAD = null;
		}
	}
};

muRotate.modes = function(){
	var css3Transform;
	
	function initImg(img, container){
		$$OBEA.setStyle(img, {
			position : 'absolute',
			border : 0,
			padding : 0,
			margin : 0,
			width : 'auto',
			height : 'auto',
			visibility : 'hidden'
		});
		container.appendChild(img);
	}
	
	function getMatrix(radian, x, y){
		var Cos = Math.cos(radian),
			Sin = Math.sin(radian);
		
		return {
			M11 : Cos * x,
			M12 : -Sin * y,
			M21 : Sin * x,
			M22 : Cos * y
		};
	}
	
	return {
		css3 : {
			support : function(){
				var style = document.createElement('div').style;
				return $$OBEA.some(
					['transform', 'MozTransform', 'webkitTransform', 'OTransform'],
					function(css){
						if(css in style){
							css3Transform = css;
							return true;
						}
					}
				);
			}(),
			
			init : function(){
				initImg(this._img, this._container);
			},
			
			load : function(){
				var img = this._img;
				$$OBEA.setStyle(img, {
					top : (this._clientHeight - img.height) / 2 + 'px',
					left : (this._clientWidth - img.width) / 2 + 'px',
					visibility : 'visible'
				});
			},
			
			show : function(){
				var matrix = getMatrix(this._radian, this._y, this._x);
				
				this._img.style[css3Transform] = 'matrix('
					+ matrix.M11.toFixed(16) + ',' + matrix.M21.toFixed(16) + ','
					+ matrix.M12.toFixed(16) + ',' + matrix.M22.toFixed(16) + ', 0, 0)';
			},
			
			destroy : function(){
				this._container.removeChild(this._img);
			}
		},
		
		filter : {
			support : function(){
				return 'filters' in document.createElement('div');
			}(),
			
			init : function(){
				initImg(this._img, this._container);
				this._img.style.filter = 
					"progid:DXImageTransform.Microsoft.Matrix(SizingMethod='auto expand')";
			},
			
			load : function(){
				this._img.onload = null;
				this._img.style.visibility = 'visible';
			},
			
			show : function(){
				var img = this._img;
				$$OBEA.extend(
					img.filters.item('DXImageTransform.Microsoft.Matrix'),
					getMatrix(this._radian, this._y, this._x)
				);
				img.style.top = (this._clientHeight - img.offsetHeight) / 2 + 'px';
				img.style.left = (this._clientWidth - img.offsetWidth) / 2 + 'px';
			},
			
			destroy : function(){
				this._container.removeChild(this._img);
			}
		},
		
		canvas : {
			support : function(){
				return 'getContext' in document.createElement('canvas');
			}(),
			
			init : function(){
				var 
					canvas = this._canvas = document.createElement('canvas'),
					context = this._context = canvas.getContext('2d');
				
				$$OBEA.setStyle(canvas, {
					position : 'absolute',
					left : 0,
					top : 0
				});
				
				canvas.width = this._clientWidth;
				canvas.height = this._clientHeight;
				this._container.appendChild(canvas);
			},
			
			show : function(){
				var img = this._img,
					context = this._context,
					clientWidth = this._clientWidth,
					clientHeight = this._clientHeight;
					
				context.save();
				context.clearRect(0, 0, clientWidth, clientHeight);
				context.translate(clientWidth/2, clientHeight/2);
				context.rotate(this._radian);
				context.scale(this._y, this._x);
				context.drawImage(img, -img.width/2, -img.height/2);
				context.restore();
			},
			
			destroy : function(){
				this._container.removeChild(this._canvas);
				this._canvas = this._context = null;
			}
		}
	};
}();

muRotate.transforms = {
	vertical : function(){
		this._radian = Math.PI - this._radian;
		this._y *= -1;
	},
	horizontal : function(){
		this._radian = Math.PI - this._radian;
		this._x *= -1;
	},
	rotate : function(radian){
		this._radian = radian;
	},
	left : function(){
		this._radian -= Math.PI/2;
	},
	right : function(){
		this._radian += Math.PI/2;
	},
	rotatebydegress : function(degress){
		this._radian = degress * Math.PI/180;
	},
	scale : function(){
		function getZoom(scale, zoom){
			return scale > 0 && scale > -zoom ? zoom :
				   scale < 0 && scale < zoom ? -zoom : 0;
		}
		return function(zoom){
			if(zoom){
				var 
					hZoom = getZoom(this._y, zoom),
					vZoom = getZoom(this._x, zoom);
				if(hZoom && vZoom){
					this._y += hZoom;
					this._x += vZoom;
				}
			}
		}
	}(),
	zoomin : function(){
		this.scale(Math.abs(this._zoom));
	},
	zoomout : function(){
		this.scale(-Math.abs(this._zoom));
	}
};

muRotate.prototype._init = function(){
	var 
		init = muRotate.prototype._init,
		methods = {
			'init' : function(){
				this._mrX = this.mrY = this._mrRadian = 0;
				this._mrSTART = $$OBEA.bind(start, this);
				this._mrMOVE = $$OBEA.bind(move, this);
				this._mrSTOP = $$OBEA.bind(stop, this);
			},
			'initContainer' : function(){
				$$OBEA.helpe.addEvent(this._container, 
										'mousedown', this._mrSTART);
			},
			'destroy' : function(){
				$$OBEA.helpe.removeEvent(this._container, 
										'mousedown', this._mrSTART);
				this._mrSTOP();
				this.mrSTART = this._mrMOVE = this._mrSTOP = null;
			}
		};
	
	function start(e){
		var rect = $$OBEA.clientRect(this._container);
		this._mrX = rect.left + this._clientWidth / 2;
		this._mrY = rect.top + this._clientHeight / 2;
		this._mrRadian = Math.atan2( e.clientY - this._mrY, 
							e.clientX - this._mrX) - this._radian;
		$$OBEA.helpe.addEvent(document, 'mousemove', this._mrMOVE);
		$$OBEA.helpe.addEvent(document, 'mouseup', this._mrSTOP);
		if($$OBEA.browser.ie){
			var container = this._container;
			$$OBEA.helpe.addEvent(container, 'losecapture', this._mrSTOP);
			container.setCapture();
		}else{
			$$OBEA.helpe.addEvent(window, 'blur', this._mrSTOP);
			e.preventDefault();
		}
	}
	
	function move(e){
		this.rotate(Math.atan2(e.clientY - this._mrY, 
							e.clientX - this._mrX) - this._mrRadian);
		window.getSelection ? window.getSelection().removeAllRanges() :
									document.selection.empty();
	}
	
	function stop(){
		$$OBEA.helpe.removeEvent(document, 'mousemove', this._mrMOVE);
		$$OBEA.helpe.removeEvent(document, 'mouseup', this._mrSTOP);
		if($$OBEA.browser.ie){
			var container = this._container;
			$$OBEA.helpe.removeEvent(container, 'losecapture', this._mrSTOP);
			container.releaseCapture();
		}else{
			$$OBEA.helpe.removeEvent(window, 'blur', this._mrSTOP);
		}
	}
	return function(){
		var options = arguments[0][1];
		if(!options || options.mouseRotate !== false){
			$$OBEA.forEach(methods, function(method, name){
				$$OBEA.selfe.addEvent(this, name, method);
			}, this);
		}
		init.apply(this, Array.prototype.slice.apply(arguments));
	}
}();


muRotate.prototype._init = function(){
	var 
		init = muRotate.prototype._init,
		mousewheel = $$OBEA.browser.firefox ? 'DOMMouseScroll' : 'mousewheel',
		methods = {
			'init' : function(){
				this._mzZoom = $$OBEA.bind(zoom, this);
			},
			'initContainer' : function(){
				$$OBEA.helpe.addEvent(this._container, 
										mousewheel, this._mzZoom);
			},
			'destroy' : function(){
				$$OBEA.helpe.removeEvent(this.container,
										mousewheel, this._mzZoom);
				this._mzZoom = null;
			}
		};
	
	function zoom(e){
		this.scale((
			e.wheelDelta ? e.wheelDelta / (-120) : (e.detail || 0) / 3
		) * Math.abs(this._zoom));
		e.preventDefault();
	}
	
	return function(){
		var options = arguments[0][1];
		if(!options || options.mouseZoom !== false){
			$$OBEA.forEach(methods, function(method, name){
				$$OBEA.selfe.addEvent(this, name, method);
			}, this);
		}
		init.apply(this, Array.prototype.slice.apply(arguments));
	}
}();

function $$(id){
	return document.getElementById(id);
}

var 
	container = $$('idContainer'),
	src = 'http://images.cnblogs.com/cnblogs_com/cloudgamer/143727/r_mm14.jpg',
	gif = 'http://images.cnblogs.com/cnblogs_com/cloudgamer/169629/o_loading.gif',
	options = {
		onPreLoad : function(){
			container.style.backgroundImage = "url('" + gif +"')";
			
		},
		onLoad : function(){
			container.style.backgroundImage = "";
		},
		onError : function(err){
			container.style.backgroundImage = "";
			alert(err);
		}
	},
	it = mooluRotate(container, options);
	

it.load(src);		

})(window)